"""
PV管理器模块

该模块实现了EPICS PV的管理功能，提供了PV连接、监控和回调处理等功能。
主要功能包括：
1. PV连接管理：创建和维护PV连接
2. 回调处理：处理PV值变化的回调
3. 连接状态监控：检查PV连接状态
4. 观察者模式：支持PV值变化的通知机制

主要组件：
- PVManager：PV管理器类，继承自Subject
- PVObserver：PV观察者类，用于处理PV值变化

使用示例：
    pv_manager = PVManager(pv_dict)
    pv_manager.set_callback('power', on_power_change)
    if pv_manager.wait_for_connection():
        print("PV连接成功")
"""

from typing import Dict, Any, List, Optional, Callable
from epics import PV
from .observer import Subject, PVObserver

class PVManager(Subject):
    """
    PV管理器类
    
    负责管理EPICS PV的连接、监控和回调处理。实现了观察者模式，
    支持多个观察者订阅PV值变化事件。
    
    主要功能：
    1. PV连接管理
       - 创建PV连接
       - 维护PV连接状态
       - 检查连接状态
    
    2. 回调处理
       - 设置PV值变化回调
       - 处理PV值变化事件
       - 通知观察者
    
    3. 连接状态监控
       - 检查所有PV连接状态
       - 等待PV连接建立
       - 超时处理
    
    属性：
        pv_dict (Dict[str, str]): PV配置字典，键为别名，值为PV名称
        pvs (Dict[str, PV]): PV对象字典，键为别名，值为PV对象
    
    方法：
        get_pv(): 获取PV对象
        set_callback(): 设置PV回调函数
        check_connection(): 检查PV连接状态
        wait_for_connection(): 等待PV连接建立
        get_pv_value(): 获取PV值
    """
    
    def __init__(self, pv_dict: Dict[str, str]):
        """
        初始化PV管理器
        
        创建PV连接并初始化观察者列表。
        
        Args:
            pv_dict: PV配置字典，键为PV别名，值为实际PV名称
                    例如：{'power': 'RFQ:Power'}
        """
        super().__init__()
        self.pv_dict = pv_dict
        self.pvs: Dict[str, PV] = {}
        
        # 创建PV连接
        for alias, pv_name in pv_dict.items():
            self.pvs[alias] = PV(pv_name)
            
    def get_pv(self, alias: str) -> PV:
        """
        获取PV对象
        
        通过别名获取对应的EPICS PV对象。
        
        Args:
            alias: PV别名
            
        Returns:
            PV: EPICS PV对象
            
        Raises:
            KeyError: 当别名不存在时抛出
        """
        if alias not in self.pvs:
            raise KeyError(f"未找到PV别名: {alias}")
        return self.pvs[alias]
        
    def get_pv_value(self, alias: str) -> Any:
        """
        获取PV值
        
        通过别名获取对应的EPICS PV值。
        
        Args:
            alias: PV别名
            
        Returns:
            Any: PV的当前值
            
        Raises:
            KeyError: 当别名不存在时抛出
            ValueError: 当PV未连接或值无效时抛出
        """
        pv = self.get_pv(alias)
        if not pv.connected:
            raise ValueError(f"PV {alias} 未连接")
        if pv.value is None:
            raise ValueError(f"PV {alias} 值无效")
        return pv.value
        
    def set_callback(self, alias: str, callback: Callable) -> None:
        """
        设置PV回调函数
        
        为指定的PV设置值变化回调函数，并创建观察者。
        
        Args:
            alias: PV别名
            callback: 回调函数，接收PV值变化事件
            
        Raises:
            KeyError: 当别名不存在时抛出
        """
        if alias not in self.pvs:
            raise KeyError(f"未找到PV别名: {alias}")
            
        observer = PVObserver(callback)
        self.attach(observer)
        self.pvs[alias].add_callback(self._pv_callback)
        
    def _pv_callback(self, pvname: str = None, value: Any = None, **kwargs) -> None:
        """
        PV值变化回调函数
        
        处理PV值变化事件，并通过观察者模式通知订阅者。
        
        Args:
            pvname: PV名称
            value: 新的PV值
            **kwargs: 其他参数
        """
        # 通过PV名称找到对应的别名
        alias = next((k for k, v in self.pv_dict.items() if v == pvname), None)
        if alias:
            self.notify({'alias': alias, 'value': value})
            
    def check_connection(self) -> bool:
        """
        检查PV连接状态
        
        检查所有PV是否都已成功连接。
        
        Returns:
            bool: 所有PV是否都已连接
        """
        return all(pv.connected for pv in self.pvs.values())
        
    def wait_for_connection(self, timeout: float = 10.0) -> bool:
        """
        等待PV连接
        
        等待所有PV连接建立，直到超时或全部连接成功。
        
        Args:
            timeout: 超时时间（秒），默认10秒
            
        Returns:
            bool: 是否所有PV都已连接
        """
        import time
        start_time = time.time()
        while time.time() - start_time < timeout:
            if self.check_connection():
                return True
            time.sleep(0.1)
        return False 